/*
 * =====================================================================================
 *
 *       Filename:  getProcInfo.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  19.4.2013 10:27:00
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *   Organization:  
 *
 * =====================================================================================
 */

#include <linux/module.h>
#include <linux/kernel.h>

#include <linux/sched.h>

#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>

#define MAX_PID 32768
#define MAX_PID_LEN 6

const char *FILENAME = "ibpProcInfo.ibp";

const struct task_struct *savedTask;
char *comm;
int commLen;
char wantedPid[MAX_PID_LEN];
char wasWrite;

struct task_struct *findByPid(int wantedPid)
{
    struct task_struct *task;

    for_each_process(task) {
        if(task->pid == wantedPid) {
            return task;
        } 
    }

    return NULL;
}

int storeInfo(const struct task_struct *task)
{
    int len, i; 
    commLen = strlen(task->comm)+1;
    if(comm != NULL) {
        kfree(comm);
    }
    comm = (char *)kmalloc(commLen*sizeof(char), GFP_KERNEL);
    if(comm == NULL) {
        printk(KERN_INFO "getProcInfo: Chyba pri alokaci pameti");
        return 0;
    }

    snprintf(comm, commLen, "%s", task->comm);
    return 1;
}

static int procInfoRead(char *page, char **start, off_t off, int len,
        int *eof, void *data)
{
    int endIndex;
    int writeLen;
    int ret;


    // Pokud nebylo nikdy zapsano, neni znam proces o kterem hledame info
    if(!wasWrite) {
            printk(KERN_INFO "getProcInfo: Zadost o cteni pred zapisem");
            printk(KERN_INFO "");
        return -1;
    }
    
    // Jeste jsme nenacetly vsechny informace
    if(off <= commLen) {
        endIndex = off + len;
        writeLen = len;
        if(endIndex >= commLen) {   // Dostali bysme se za hranice textu
            writeLen = commLen - off;
            *eof = 1;
            ret = snprintf(page, writeLen, "%s", &savedTask->comm[off]); 

        }
        else {
            ret = snprintf(page, writeLen, "%s", &savedTask->comm[off]); 

            printk(KERN_INFO "");
        }
    }
    else {
        printk(KERN_INFO "procsInfo: procInfoRead zadost o cteni mimo meze");
        printk(KERN_INFO "");
        *eof = 1;
        return 0;
    }
    
    return ret;
}

static int procInfoWrite(struct file *file, const char *buff,
        unsigned long len, void *data)
{
    long pid;

    if(len > MAX_PID_LEN) {
        printk(KERN_INFO "procsInfo: procInfoWrite zadost o zapisu prilis velkych dat");
        printk(KERN_INFO "");
        return -1;
    }

    // Ziskani pid textove
    if(copy_from_user(wantedPid, buff, len)) {
        return -2;
    }

    // Prevedeni pid + testy
    if(strict_strtol(wantedPid, 10, &pid) < 0) {
        printk(KERN_INFO "procsInfo: procInfoWrite chybne pid");
        printk(KERN_INFO "");
        return -3;
    }
    if(pid <= 0 || pid > MAX_PID) {
        printk(KERN_INFO "procsInfo: procInfoWrite pid mimo meze");
        printk(KERN_INFO "");
        return -3;
    }

    // Nalezeni prislusne task_struct
    if((savedTask = findByPid(pid)) == NULL) {
        printk(KERN_INFO "procsInfo: nepodarilo se najit task_struct s uvedenym pid");
        printk(KERN_INFO "");
        return -3;
    }

    if(storeInfo(savedTask) <= 0) {
        return -3;
    }
    
    wasWrite = 1;
    return len;
}


int init_module(void)
{
    struct proc_dir_entry *procInfoFile;

    procInfoFile = create_proc_entry(FILENAME, 0666, NULL);
    if(procInfoFile == NULL) {
        printk(KERN_INFO "getProcInfo: Nepodarilo se vytvorit soubor v proc");
        printk(KERN_INFO "");
        return -1;
    }

    procInfoFile->read_proc = procInfoRead;
    procInfoFile->write_proc = procInfoWrite;
    wasWrite = 0;
    comm = NULL;

    printk(KERN_INFO "getProcInfo: Modul zaveden");
    printk(KERN_INFO "");
    return 0;
}

void cleanup_module(void)
{
    remove_proc_entry(FILENAME, NULL);
    if(comm != NULL) {
        kfree(comm);
    }

    printk(KERN_INFO "getProcInfo: Modul odebran");
    printk(KERN_INFO "");
}
